package uit.nfcmenu.webservice;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;

import org.json.JSONException;
import org.json.JSONObject;

import uit.nfcmenu.db.adapter.OrderAdapter;
import uit.nfcmenu.db.model.ItemModel;
import uit.nfcmenu.db.model.MenuModel;
import uit.nfcmenu.db.model.OrderModel;
import uit.nfcmenu.util.CommConstant;
import uit.nfcmenu.util.NetworkHelper;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.Log;


public class WSMapping {
	static String tag = WSMapping.class.getSimpleName();

	public static boolean isMenusChanged = false;
	public static boolean isItemsChanged = false;
	public static boolean isOrdersChanged = false;

	public static final int TIMEOUT_CONNECTION = 10000;

	public static UserModel login(Context context, String username, String password,
			String deviceId) throws MyException {
		UserModel model = null;
		
		String url = CommonWS.User.createUrlPostLogin();
		JSONObject body = createLoginJson(username, password, deviceId);
		if (body != null) {
			String response = null;
			try {
				response = post(url, body);
			} catch (Exception e) {
				Log.w(tag, "Error ", e);
			}
			if (response != null) { 
				//Log.i(tag, "response=" + response);
				model = JSONParser.parseUser(response);
			}
		}

		return model;
	}

	// {"username":"user","password":"123456","deviceid":"12345678"}
	public static JSONObject createLoginJson(String username, String password, String deviceId) {
		JSONObject object = new JSONObject();
		try {
			object.put(CommonWS.User.JSON_USERNAME, username);
			object.put(CommonWS.User.JSON_PASSWORD, password);
			object.put(CommonWS.User.JSON_DEVICE_ID, (deviceId==null)?"":deviceId);
		} catch (JSONException e) {
			e.printStackTrace();
			return null;
		}
		Log.i(tag, "createLoginJson() return object = "+object.toString());
		return object;
	}

	public static boolean logout(String username, String deviceId) {
		String url = CommonWS.User.createUrlLogout(username, deviceId);
		Log.w(tag, "logout() url=" + url);
		String response = null;
		try {
			response = callWS(url);
		} catch (MyException e) {
			Log.e(tag, "Error " + e);
		}
		// parse
		if (response != null && CommConstant.SIGN_TRUE.equals(response)) { // FIXME hard code 4 test
			return true;
		}
		return false;
	}

	private static int getNotifyDataServerChanged(Context context, int type)
			throws MyException {
		String resID = PreferenceHelper.loadRestaurantId(context);
		String url = CommonWS.createUrlGetNotify(resID);
		String response = callWS(url);
		if (response != null) {
			return JSONParser.parseNotify(context, response, type);
		}
		return -1;
	}
	
	public static ArrayList<MenuModel> getAllMenusFromServer(Context context)
			throws MyException {
		ArrayList<MenuModel> models = null;
		
		// check if data in server changed
		int type = CommConstant.CHANGED_MENU;
		int oldVersion = PreferenceHelper.loadVersion(context, type);
		int newVersion = getNotifyDataServerChanged(context, type);
		Log.w(tag, "getAllMenuFromServer() oldVersion="+oldVersion
				+" vs newVersion="+newVersion);
		if (newVersion > oldVersion) {
			isMenusChanged = true;
			// get stream
			String resID = PreferenceHelper.loadRestaurantId(context);
			String url = CommonWS.Menu.createUrlGetMenus(resID);
			String response = callWS(url);
			if (response != null) {
				models = JSONParser.parseMenus(response);
			}
			PreferenceHelper.saveVersion(context, type, newVersion);
		}
		return models;
	}

	public static ArrayList<ItemModel> getAllItemsFromServer(Context context)
			throws MyException {
		ArrayList<ItemModel> models = null;
		
		// check if data in server changed
		int type = CommConstant.CHANGED_ITEM;
		int oldVersion = PreferenceHelper.loadVersion(context, type);
		int newVersion = getNotifyDataServerChanged(context, type);
		Log.w(tag, "getAllItemsFromServer() oldVersion="+oldVersion
				+" vs newVersion="+newVersion);
		if (newVersion > oldVersion) {
			isItemsChanged = true;
			// get stream
			String resID = PreferenceHelper.loadRestaurantId(context);
			String url = CommonWS.Item.createUrlGetItems(resID);
			String response = callWS(url);
			// parse
			if (response != null) {
				models = JSONParser.parseItems(response);
			}
			PreferenceHelper.saveVersion(context, type, newVersion);
		}
		return models;
	}

	public static ArrayList<OrderModel> getAllOrderFromServer(Context context)
			throws MyException {
		ArrayList<OrderModel> models = null;
		
		// check if data in server changed
		int type = CommConstant.CHANGED_ORDER;
		int oldVersion = PreferenceHelper.loadVersion(context, type);
		int newVersion = getNotifyDataServerChanged(context, type);
		Log.w(tag, "getAllOrderFromServer() oldVersion="+oldVersion
				+" vs newVersion="+newVersion);
		if (newVersion > oldVersion) {
			isOrdersChanged = true;
			// get stream
			String resID = PreferenceHelper.loadRestaurantId(context);
			String url = CommonWS.Order.createUrlGetOrders(resID, oldVersion);
			String response = callWS(url);
			// parse
			if (response != null) {
				models = JSONParser.parseOrders(response);
			}
			PreferenceHelper.saveVersion(context, type, newVersion);
		}
		return models;
	}

	/**
	 * @return
	 *  1: posted
	 *  0: post fail
	 *  -1: put request to queue (in CommConstant.savedRequests)
	 * @throws MyException
	 */
	public static int postOrder(Context context, OrderModel order)
			throws MyException {
		String resID = PreferenceHelper.loadRestaurantId(context);
		String user = PreferenceHelper.loadUsername(context);
		String url = CommonWS.Order.createUrlPostOrder(resID, user,
				order.getItemID(), order.getStatus(), order.getTableNo(),
				order.getQuantity(), order.getComment());
		
		if (NetworkHelper.checkNetworkStatus(context)) {
			String response = null;
			try {
				response = callWS(url);
			} catch (MyException e) {
				throw e;
			}
			if (response != null && CommConstant.SIGN_TRUE.equals(response)) {
				return 1;
			}
		} else {
			CommConstant.savedRequests.add(url);
			return -1;
		}
		return 0;
	}

	/**
	 * @return
	 *  1: posted
	 *  0: post fail
	 *  -1: put request to queue (in CommConstant.savedRequests)
	 * @throws MyException
	 */
	public static int changeOrderStatus(Context context, OrderModel model) 
			throws MyException {
		String url = CommonWS.Order.createUrlChangeOrderStatus(model.getId(),
				model.getStatus(), model.getComment());

		if (NetworkHelper.checkNetworkStatus(context)) {
			String response = null;
			try {
				response = callWS(url);
			} catch (MyException e) {
				Log.e(tag, "changeOrderStatus() Exception: ", e);
				throw e;
			}
			if (response != null && CommConstant.SIGN_TRUE.equals(response)) {
				new OrderAdapter(context).updateOrderModel(model);
				return 1;
			} 
		} else {
			CommConstant.savedRequests.add(url);
			return -1;
		}
		return 0;
	}
	
	public Drawable getBgDrawable() {
		Drawable drawable = null;
		
		return drawable;
	}

	public static String callWS(String url) throws MyException {
		//Log.w(tag, "callWS() url=" + url);
		String response = null;
		try {

			URL myUrl = new URL(url);
			HttpURLConnection con = (HttpURLConnection) myUrl.openConnection();
			con.setConnectTimeout(TIMEOUT_CONNECTION);
			con.setReadTimeout(TIMEOUT_CONNECTION);
			InputStream ins = con.getInputStream();
			InputStreamReader isr = new InputStreamReader(ins);
			BufferedReader in = new BufferedReader(isr);

			String inputLine;
			String temp = "";
			while ((inputLine = in.readLine()) != null) {
				temp += inputLine;
			}

			in.close();
			response = temp;
		} catch (Exception e) {
			Log.w(tag, "Error!", e);
		}

		//Log.w(tag, "response="+response);
		return response;
	}
	
	// ==================================
	// Post Methods
	// ==================================
	
	public static String post(String link, JSONObject value)
			throws Exception {
		Log.v(tag, "parsePost() link="+link+", jo=" + value.toString(1));
		
		URL url = new URL(link);
		URLConnection conn = url.openConnection();
		conn.setConnectTimeout(TIMEOUT_CONNECTION);
		conn.setReadTimeout(TIMEOUT_CONNECTION);
		((HttpURLConnection) conn).setRequestMethod("POST");
		conn.setDoOutput(true);
		conn.setDoInput(true);
		conn.setRequestProperty("Content-Type", "application/json");
		conn.setRequestProperty("Content-Length", "" + value.toString().length());
		OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
		wr.write(value.toString());
		wr.flush();

		// Get the response
		BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
		String inputLine;
		// int i = conn.getConnectTimeout();
		// Log.e("GetJson", "int i Timeout" + String.valueOf(i));

		String result = "";
		while ((inputLine = in.readLine()) != null)
			result += inputLine;
		return result;
	}
		
	/*private static void post(String endpoint, Map<String, String> params)
			throws IOException {
		URL url;
		try {
			url = new URL(endpoint);
		} catch (MalformedURLException e) {
			throw new IllegalArgumentException("invalid url: " + endpoint);
		}
		StringBuilder bodyBuilder = new StringBuilder();
		Iterator<Entry<String, String>> iterator = params.entrySet().iterator();
		// constructs the POST body using the parameters
		while (iterator.hasNext()) {
			Entry<String, String> param = iterator.next();
			bodyBuilder.append(param.getKey()).append('=')
					.append(param.getValue());
			if (iterator.hasNext()) {
				bodyBuilder.append('&');
			}
		}
		String body = bodyBuilder.toString();
		Log.v(tag, "Posting '" + body + "' to " + url);
		byte[] bytes = body.getBytes();
		HttpURLConnection conn = null;
		try {
			conn = (HttpURLConnection) url.openConnection();
			conn.setDoOutput(true);
			conn.setUseCaches(false);
			conn.setFixedLengthStreamingMode(bytes.length);
			conn.setRequestMethod("POST");
			conn.setRequestProperty("Content-Type",
					"application/x-www-form-urlencoded;charset=UTF-8");
			// post the request
			OutputStream out = conn.getOutputStream();
			out.write(bytes);
			out.close();
			// handle the response
			Log.v(tag, "response " + conn.getResponseMessage());
			int status = conn.getResponseCode();
			Log.v(tag, "response " + conn.getResponseMessage());
			if (status != 200) {
				throw new IOException("Post failed with error code " + status);
			}
		} finally {
			if (conn != null) {
				conn.disconnect();
			}
		}
	}*/
}
